package com.zdp.rabbitmq.send;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author sesshomaru
 * @date 2019/11/25 10:46
 */
@Component
public class RabbitSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 这个只判断 消息生产方是否可以将消息路由到rabbitmq的broker上 这里是是否可以路由到 交换机上 而不是 是否可以路由到
     * 队列上，这里主要关注这个消息是否可以到 交换机上  交换机 + 队列 可以看作是一个broker
     */
    //回调函数: confirm确认
    final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            System.err.println("correlationData: " + correlationData);
            System.err.println("ack: " + ack);
            if(!ack){
                //可以进行日志记录、异常处理、补偿处理等
                System.err.println("异常处理....");
            }else {
                //更新数据库，可靠性投递机制
            }
        }
    };


    //回调函数: return返回
    final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
        @Override
        public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText,
                                    String exchange, String routingKey) {
            System.err.println("return exchange: " + exchange + ", routingKey: "
                    + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
        }
    };


    //发送消息方法调用: 构建Message消息
    public void send(Object message, Map<String, Object> properties) throws Exception {
        MessageHeaders mhs = new MessageHeaders(properties);
        Message msg = MessageBuilder.createMessage(message, mhs);
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.setReturnCallback(returnCallback);
        //id + 时间戳 全局唯一  用于ack保证唯一一条消息,这边做测试写死一个。但是在做补偿策略的时候，必须保证这是全局唯一的消息
        CorrelationData correlationData = new CorrelationData("1234567890");

        //目前存在的交换机为exchange001路由key 	springboot.#
        /**
         * 1.当路由key错误
         * 当使用正确的exchange001  错误的spring1231boot.abc 路由key时 confirmCallback 中的ack是true 但是  returnCallback
         * 中会打印需要发布的消息信息 因为路由key错误导致
         */
        /**
         * 2.当服务将消息发送到 broker端时 也就是无法进入交换机
         * 这里使用错误的交换机 exchange0011 就会直接进入 confirmCallback 的异常中 这里可以对需要发送的消息进行
         * 可以进行日志记录、异常处理、补偿处理等
         */
     //   rabbitTemplate.convertAndSend("exchange0011", "spring1231boot.abc", msg, correlationData);
        rabbitTemplate.convertAndSend("exchange001","springboot.abc",msg);
    }

}
